<?php

/**
 * uniBoard Applications Core
 *
 * Light and fast forum solution for web 2.0-like communities.
 *
 * @package		uniBoard
 * @author		Rafał Pitoń
 * @license		http://www.gnu.org/licenses/gpl-3.0.html
 * @since		Version 0.1
 * 
 * ------------------------------------------------------------------------
 * 
 * $Date: 2010-09-20 21:23:27 +0000 (Mon, 20 Sep 2010) $
 * $Revision: 64 $
 * $Author: rafio.xudb@gmail.com $
 */

// ------------------------------------------------------------------------

class appCore{
	
	/**
	 * Software configuration
	 *
	 * @var array
	 */
	
	public $conf 			= array();
	
	/**
	 * Our language strings array
	 *
	 * @var array
	 */
	
	public $lang 			= array();

	/**
	 * Our language overloaded id
	 *
	 * @var integer
	 */
	
	public $lang_over_id	= 0;
	
	/**
	 * Our language overloaded file
	 *
	 * @var string
	 */
	
	public $lang_over_file	= 'NULL';
	
	/**
	 * Currently logged in user
	 *
	 * @var array
	 */
	
	public $user			= array();
	
	/**
	 * User's ACL
	 *
	 * @var array
	 */
	
	public $user_acl		= array();
	
	/**
	 * Client IP
	 *
	 * @var string
	 */
	
	public $client_ip		= '';
	
	/**
	 * Client Agent
	 *
	 * @var string
	 */
	
	public $client_agent	= '';
	
	/**
	 * Client IP is Banned?
	 *
	 * @var bool
	 */
	
	public $banned_ip		= false;
	
	/**
	 * Last Ban check Reason
	 *
	 * @var string
	 */
	
	public $ban_reason		= false;
	
	/**
	 * Session ID from URL? (causes URL to be inside links)
	 *
	 * @var bool
	 */
	
	public $sid_url 		= false;
	
	/**
	 * Currently loaded templates groups
	 *
	 * @var array
	 */
	
	public $templates		= array();

	/**
	 * Our cache store
	 *
	 * @var array
	 */
	
	public $cache_store		= array();
	
	/**
	 * Generation start microtime
	 *
	 * @var float
	 */
	
	public $gen_clock		= 0;

	/**
	 * Generation start time
	 *
	 * @var integer
	 */
	
	public $time			= 0;

	/**
	 * Used Time Zone correction (timezone * 3600)
	 *
	 * @var integer
	 */
	
	public $time_zone		= 0;
	
	/**
	 * Use DST?
	 *
	 * @var bool
	 */
	
	public $time_dst		= false;
	
	/**
	 * Database connection class
	 *
	 * @var object
	 */
	
	public $db 				= NULL;
	
	/**
	 * Database queries number
	 *
	 * @var integer
	 */
	
	public $db_queries		= 0;
	
	/**
	 * Database queries list
	 *
	 * @var array
	 */
	
	public $db_queries_l	= array();
	
	/**
	 * Session handler
	 *
	 * @var object
	 */
	
	public $session 		= NULL;
	
	/**
	 * Number - every request for number returns value and increases it by 1
	 *
	 * @var integer
	 */
	
	private $number 		= 0;
	
	/**
	 * Static Style ID for autoloader
	 *
	 * @var integer
	 */
	
	public static $style 	= 0;
	
	/**
	 * Files Helper Class
	 *
	 * @var object
	 */
	
	public $files			= NULL;
	
	/**
	 * Users Helper Class
	 *
	 * @var object
	 */
	
	public $users			= NULL;
	
	// ------------------------------------------------------------------------

	/**
	 * Initialises our main class
	 *
	 */
	
	function __construct(){
		
		// Set generation clock
		$this -> gen_clock = microtime( true);
		
		// Set constant timestamp for functions requiring identical time all the time
		$this -> time = time();
		
		// Check directories permissions
		try
		{
			if ( !USE_MB_STRING)
			{
				// We need mb_string to work
				throw new exc_critical( 'GEN', 'Multibyte String Extension could not be found.', 'mb_string extension not avaiable.');
			}
			
			if ( ini_get( 'mbstring.func_overload') != 0 && ini_get( 'mbstring.func_overload') != 4)
			{
				// mb_string function overloading will mess with our code
				throw new exc_critical( 'GEN', 'Multibyte String Function Overloading must be set to either 0 or 4.', 'mbstring.func_overload is set to &quot;' . ini_get( 'mbstring.func_overload') . '&quot;');
			}
			
			if ( ini_get( 'mbstring.http_input') != 'pass' || ini_get( 'mbstring.http_output') != 'pass')
			{
				// mb_string configuration will mess with our code
				throw new exc_critical( 'GEN', 'HTTP Input and Output conversion should be set to &quot;pass&quot;', 'mbstring.http_input is set to &quot;' . ini_get( 'mbstring.http_input') . '&quot;<br />mbstring.http_output is set to &quot;' . ini_get( 'mbstring.http_output') . '&quot;');
			}
			
			if ( !file_exists( CONFIG_PATH))
			{
				// Cache must be writeable
				throw new exc_critical( 'FILE', 'Your board has not yet been installed or configured.', CONFIG_PATH . ' does not exist.');
			}
			
			// Include config
			require_once( CONFIG_PATH);
			
			if ( !PRODUCT_INSTALLED)
			{
				// Cache must be writeable
				throw new exc_critical( 'FILE', 'Your board has not yet been installed or configured.', 'Board is not installed.');
			}
			
			if ( !is_writeable( CACHE_PATH))
			{
				// Cache must be writeable
				throw new exc_critical( 'FILE', 'Cache directory must be writeable in order to run system propertly.', CACHE_PATH . ' is not writeable.');
			}			
			
			if ( !is_writeable( UPLOADS_PATH))
			{
				// Cache must be writeable
				throw new exc_critical( 'FILE', 'Uploads directory must be writeable in order to run system propertly.', UPLOADS_PATH . ' is not writeable.');			
			}			
			
			if ( !is_writeable( STYLES_DATA_PATH))
			{
				// Cache must be writeable
				throw new exc_critical( 'FILE', 'Styles directory must be writeable in order to run system propertly.', STYLES_DATA_PATH . ' is not writeable.');			
			}	
			
			// Do we hard-ban old IE browsers?
	    	if ( FORBID_OLD_IE > 0 && strpos( $_SERVER[ 'HTTP_USER_AGENT'], 'MSIE') !== false && substr( $_SERVER[ 'HTTP_USER_AGENT'], strpos( $_SERVER[ 'HTTP_USER_AGENT'], 'MSIE') + 5, 1) < FORBID_OLD_IE)
	    	{
	    		// We are blocking IE older than 8
	    		throw new exc_critical( 'GEN', 'Your browser fails to met compatibility requirements of this software.', 'Your browser is outdated, and thus unable to met compatibility requirements to run this software.');
	    	}
	    
			// Create Database connection
			$this -> db = new class_db( $this, $db_data['db_host'] . ':' . $db_data['db_port'], $db_data['db_name'], $db_data['db_user'], $db_data['db_pass']);
		}
		catch ( exc_critical $exception)
		{
			// Kill script runtime
			die( $exception);
		}

		// Set hard keys for language strings
		$this -> lang_keys = array(
										'PRODUCT_NAME' => PRODUCT_NAME,
										'PRODUCT_VERSION_LABEL' => PRODUCT_VERSION_LABEL,
									);
		
		// Find out user IP 
		if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ))
	    {
	    	$this -> client_ip = $_SERVER['HTTP_CLIENT_IP'];
	    }
	    elseif ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ))
	    {
	    	$this -> client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
	    }
	    else
	    {
	    	$this -> client_ip = $_SERVER['REMOTE_ADDR'];
	    }
	    
    	// Let us store user agent in main class
    	$this -> client_agent = $_SERVER[ 'HTTP_USER_AGENT'];
    	
		// Load system configuration from Cache
		$this -> conf = class_cache::loadCache( 'configuration');
		
		// If load did not succeeded, build new cache
		if ( class_cache::$load_error)
		{
			// Perform settings select
			$this -> db -> query( 'SELECT setting_id, setting_value
			FROM ' . DB_PREFIX . 'settings');
			
			// Parse result as MySQL one
			while ( $setting_result = $this -> db -> fetch_array())
			{
				// Put setting into array
				$this -> conf[$setting_result[0]] = $setting_result[1];
			}
			
			// Store in cache
			class_cache::saveCache( 'configuration', $this -> conf);
			
			// Free memory
			$this -> db -> freeResult();
			unset( $setting_result, $settings_sql);
		}
			
		// Start Helpers
		$this -> users = new class_users($this);	
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Changes system setting to new value
	 *
	 * @param string $setting_name
	 * @param string $setting_value
	 */
	
	function setConfig( $setting_name, $setting_value){
		
		// Update setting locally
		$this -> conf[$setting_name] = $setting_value;
		
		// Update setting globally
		$this -> db -> update( array( 'setting_value' => $this -> db -> strEscape( $setting_value)), 'settings', 'setting_id = \'' . $this -> db -> strEscape( $setting_name) . '\'' );
		
		// Flush cache
		class_cache::flushCache( 'configuration');
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * returns value from POST, or GET
	 *
	 * @param string $var_key
	 * @param bool $trim_content
	 * @return string
	 */
	
	function _REQ( $var_key, $trim_content = true){
		
		// Variable in POST superglobal array?
		if ( isset( $_POST[$var_key]))
		{
			// Is Array?
			if ( is_array( $_POST[$var_key]))
			{
				return array_filter( $_POST[$var_key], array( $this, 'filterArray'));
			}
			else
			{
				// Trim content?
				if ( $trim_content)
				{
					$_POST[$var_key] = trim( $_POST[$var_key]);
				}
				// Return String or Integer
				return ( ESCAPE_MAGIC_QUOTES ? stripslashes( $_POST[$var_key]) : $_POST[$var_key]);
			}
		}
		else if ( isset( $_GET[$var_key]) && !is_array( $_GET[$var_key]))
		{
			// Trim content?
			if ( $trim_content)
			{
				$_GET[$var_key] = trim( $_GET[$var_key]);
			}
			// Return GET
			return ( ESCAPE_MAGIC_QUOTES ? stripslashes( $_GET[$var_key]) : $_GET[$var_key]);
		}
		else
		{
			// Return null
			return NULL;
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Returns value from POST query
	 *
	 * @param string $var_key
	 * @param bool $trim_content
	 * @return string
	 */
	
	function _POST( $var_key, $trim_content = true){
		
		// Variable in POST superglobal array?
		if ( isset( $_POST[$var_key]))
		{
			// Is Array?
			if ( is_array( $_POST[$var_key]))
			{
				return array_map( array( $this, 'filterArray'), $_POST[$var_key]);
			}
			else
			{
				// Trim content?
				if ( $trim_content)
				{
					$_POST[$var_key] = trim( $_POST[$var_key]);
				}
				// Return String or Integer
				return ( ESCAPE_MAGIC_QUOTES ? stripslashes( $_POST[$var_key]) : $_POST[$var_key]);
			}
		}
		else
		{
			// Return null
			return NULL;
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Filter array
	 *
	 * @param string $item
	 * @return string
	 */
	
	function filterArray( $item){
		
		return ( ESCAPE_MAGIC_QUOTES ? stripslashes( trim( $item)) : trim( $item));
			
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Returns array of selects
	 *
	 * @param string $item
	 * @param bool $integer_key
	 * @param array $white_list
	 * @return array
	 */
	
	function listInput( $item, $integer_key = true, $white_list = array()){
		
		// Check whitelist?
		$do_whitelist = count( $white_list) > 0;
		
		// Item exists?
		if ( isset( $_POST[$item]) && is_array( $_POST[$item]))
		{
			// Ready array
			$ready_array = array_keys( $_POST[$item]);
			
			// Fix keys?
			if ( $integer_key)
			{
				foreach ( $ready_array as $key => $value)
				{
					// Settype
					settype( $value, 'integer');
					
					// Put it back?
					if ( !$do_whitelist || in_array( $value, $white_list))
					{
						$ready_array[$key] = $value;
					}
				}
			}
			
			// Return them
			return $ready_array;
		}
		else
		{
			// Return nothing
			return array();	
		}
		
	}
	
	/**
	 * Gets Byte from POST
	 *
	 * @param string $key
	 * @return string
	 */
	
	function getByte( $key){
		
		return ( isset( $_POST[$key]) && $_POST[$key] == 1 ? '1' : '0');
	
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Returns value from query string
	 *
	 * @param string $var_key
	 * @return string
	 */
	
	function _GET( $var_key, $force_type = false){
		
		// Variable in GET superglobal array?
		if ( isset( $_GET[$var_key]) && !is_array( $_GET[$var_key])){
			// Return GET
			return ( ESCAPE_MAGIC_QUOTES ? stripslashes( trim( $_GET[$var_key])) : trim( $_GET[$var_key]));
		}else{
			// Return null
			return NULL;
		}
		
	}

	// ------------------------------------------------------------------------

	/**
	 * Returns value from cookie
	 *
	 * @param string $name
	 * @return string
	 */
	
	function _COOKIE( $name){
		
		// Cookie baked?
		if ( isset( $_COOKIE[$this -> conf['cookie_name'] . $name]))
		{
			// Return cookie ready to devour
			return trim( $_COOKIE[$this -> conf['cookie_name'] . $name]);
		}
		else
		{
			// Return null
			return NULL;
		}

	}
	
	// ------------------------------------------------------------------------

	/**
	 * Sets cookie
	 *
	 * @param string $name
	 * @param string $value
	 * @param bool $pernament
	 */
	
	function setCookie( $name, $value, $pernament = false){
		
		// Send cookie
		setcookie( $this -> conf['cookie_name'] . $name, $value, ($this -> time + ( $pernament ? 31536000 : 86400)), $this -> conf['cookie_path'], $this -> conf['cookie_domain'], $this -> conf['cookie_secure']);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Eats (deletes) cookie
	 *
	 * @param string $name
	 */
	
	function killCookie( $name){
		
		//set cookie
		setcookie( $this -> conf['cookie_name'] . $name, '', $this -> time - 3600, $this -> conf['cookie_path'], $this -> conf['cookie_domain'], $this -> conf['cookie_secure']);

	}
	
	// ------------------------------------------------------------------------

	/**
	 * Loads language file
	 *
	 * @param string $file_name
	 * @param integer $file_overload
	 */
	
	function loadLanguageFile( $file_name, $file_overload = 0){
		
		// Try catch, we gonna trow exception if file is incorrect
		try
		{
			// Are we overloading file?
			if ( $file_overload > 0 && $file_overload != $this -> user['language'] && $this -> lang_over_id != $file_overload && $this -> lang_over_file != $file_name)
			{			
				// Check file existence
				if ( !file_exists( CACHE_PATH . 'lang_' . $file_overload . '/' . $file_name . PHP_EXT))
				{
					throw new exc_critical( 'FILE', 'Unable to load language file', $file_name . ' file does not exists.' );			
				}
				
				// Set overloaded id
				$this -> lang_over_id = $file_overload;
				
				// Set overloaded file
				$this -> lang_over_file = $file_name;
				
				// Include file
				include( CACHE_PATH . 'lang_' . $file_overload . '/' . $file_name . PHP_EXT);
			}
			else
			{				
				// Check file existence
				if ( !file_exists( CACHE_PATH . 'lang_' . $this -> user['language'] . '/' . $file_name . PHP_EXT))
				{
					throw new exc_critical( 'FILE', 'Unable to load language file', $file_name . ' file does not exists.' );			
				}
				
				// Include file
				include( CACHE_PATH . 'lang_' . $this -> user['language'] . '/' . $file_name . PHP_EXT);
			}			
		}
		catch ( exc_critical $exception)
		{
			// Kill script
			exit( $exception);
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Resets language overload
	 *
	 */
	
	function resetLangOverload(){
		
		// Are we overloading file?
		if ( $this -> lang_over_id > 0)
		{
			// Load original file
			include( CACHE_PATH . 'lang_' . $this -> user['language'] . '/' . $this -> lang_over_file . PHP_EXT);
			
			// Null overloads
			$this -> lang_over_id = 0;
			$this -> lang_over_file = NULL;
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * If string is correct lang string, it replaces it, otherwhise it returns raw string
	 *
	 * @param string $string
	 * @return string
	 */
	
	function ifString( $string){

		// String is parseable key?
		if ( substr( $string, 0, 3) == '{L:' && $string[strlen( $string) - 1] == '}')
		{
			// Extract key
			$string_key = substr( $string, 3, strlen( $string) - 4);
			
			// Key correct?
			if ( isset( $this -> lang[$string_key]))
			{
				// Return parsed string
				return $this -> lang[$string_key];
			}
			else
			{
				// Unfortunately key is incorrect, return unparsed string
				return $string;
			}
		}
		else
		{
			// Return unparsed string
			return $string;
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Basic URL in FRONTEND
	 *
	 * @param string $link_gets
	 * @param bool $force_key_code
	 * @param bool $link_amps
	 * @return string
	 */
	
	function link( $link_gets = '', $force_key_code = false, $nice_amps = true){
		
		// Start building link
		$link = ROOT_PATH . APP_FORUM_LAUNCHER;
		
		// Link gets?
		if ( !empty( $link_gets))
		{
			$link .= '?' . $link_gets;
			
			// Put session id into link?
			if ( $this -> sid_url)
			{
				$link .= '&sid=' . $this -> session -> session_id;
			}
			
			// Append KEY-CODE?
			if ( $force_key_code)
			{
				$link .= '&' . $this -> session -> session_key . '=' . $this -> session -> session_code;
			}
			
			// Decide on amps mode
			if ( $nice_amps)
			{
				$link = str_replace( '&', '&amp;', $link);
			}
		}
		else
		{
			// Put session id into link?
			if ( $this -> sid_url)
			{
				$link .= '?sid=' . $this -> session -> session_id;
			}
			
			// Append KEY-CODE?
			if ( $force_key_code)
			{
				// Dont add more than KEY-CODE
				$link .= ( $this -> sid_url ? '&' : '?') . $this -> session -> session_key . '=' . $this -> session -> session_code;
			}
		}
		
		// Return ready link
		return $link;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Nice URL in FRONTEND
	 *
	 * @param string $link_gets
	 * @param string $link_content
	 * @param bool $force_key_code
	 * @param bool $link_amps
	 * @return string
	 */
	
	function niceLink( $link_gets = '', $link_name = '', $force_key_code = false, $nice_amps = true){
		
		// Make friendly URL?
		if ( $this -> conf['urls_with_content'])
		{
			// Start with empty link
			$link = '';
			
			// Put link content?
			if ( isset( $link_name[0]))
			{
				$link .= $this -> secureFilename( $link_name, '', '-');
			}
		}
		else
		{
			// Start building link
			$link = ROOT_PATH . APP_FORUM_LAUNCHER;
		}
		
		// Link gets?
		if ( !empty( $link_gets))
		{
			$link .= '?' . $link_gets;
			
			// Put session id into link?
			if ( $this -> sid_url)
			{
				$link .= '&sid=' . $this -> session -> session_id;
			}
			
			// Append KEY-CODE?
			if ( $force_key_code)
			{
				$link .= '&' . $this -> session -> session_key . '=' . $this -> session -> session_code;
			}
			
			// Decide on amps mode
			if ( $nice_amps)
			{
				$link = str_replace( '&', '&amp;', $link);
			}
		}
		else
		{
			// Put session id into link?
			if ( $this -> sid_url)
			{
				$link .= '?sid=' . $this -> session -> session_id;
			}
			
			// Append KEY-CODE?
			if ( $force_key_code)
			{
				// Dont add more than KEY-CODE
				$link .= ( $this -> sid_url ? '&' : '?') . $this -> session -> session_key . '=' . $this -> session -> session_code;
			}
		}
		
		// Return ready link
		return $link;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Nice E-Mail URL in FRONTEND
	 *
	 * @param string $link_gets
	 * @param string $link_content
	 * @param bool $force_key_code
	 * @param bool $link_amps
	 * @return string
	 */
	
	function emailLink( $link_gets = '', $link_name = ''){
		
		// Make friendly URL?
		if ( $this -> conf['urls_with_content'])
		{
			// Start with Board Address
			$link = $this -> conf['board_address'];
			
			// Put link content?
			if ( isset( $link_name[0]))
			{
				$link .= $this -> secureFilename( $link_name, '', '-');
			}
		}
		else
		{
			// Start building link
			$link = $this -> conf['board_address'] . APP_FORUM_LAUNCHER;
		}
		
		// Link gets?
		if ( !empty( $link_gets))
		{
			$link .= '?' . $link_gets;
			
			// Put session id into link?
			if ( $this -> sid_url)
			{
				$link .= '&sid=' . $this -> session -> session_id;
			}
		}
		else if ( $this -> sid_url)
		{
			$link .= '?sid=' . $this -> session -> session_id;
		}
			
		// Return ready link
		return $link;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * URL to admin CP
	 *
	 * @param string $link_gets
	 * @param bool $link_amps
	 * @return string
	 */
	
	function adminLink( $link_gets = '', $nice_amps = true){
		
		// Start building link
		$link = ADMIN_PATH . APP_ADMIN_LAUNCHER;
		
		// Link gets?
		if ( !empty( $link_gets))
		{
			$link .= '?' . $link_gets;
			
			// Put session id into link?
			if ( $this -> sid_url)
			{
				$link .= '&sid=' . $this -> session -> session_id;
			}
			
			// Put session act-key to protect our admin session additionally
			$link .= '&' . $this -> session -> session_key . '=' . $this -> session -> session_code;
			
			// Decide on amps mode
			if ( $nice_amps)
			{
				$link = str_replace( '&', '&amp;', $link);
			}
		}
		else
		{
			// Put session id and KEY-CODE int link?
			if ( $this -> sid_url)
			{
				$link .= '?sid=' . $this -> session -> session_id . '&' . $this -> session -> session_key . '=' . $this -> session -> session_code;
			}
			else
			{
				// Dont add more than KEY-CODE
				$link .= '?' . $this -> session -> session_key . '=' . $this -> session -> session_code;
			}
		}
		
		// Return ready link
		return $link;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Generates password hash
	 *
	 * @param string $raw_text
	 * @param string $salt
	 * @return string
	 */
	
	function hashPassword( $raw_text, $salt){
		
		// Return salted password
		return md5( $raw_text . $salt);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Generates random salt
	 *
	 * @param integer $lenght
	 * @param bool $complex
	 * @return string
	 */
	
	function makeSalt( $lenght = 8, $complex = true){
		
		if ( $complex)
		{
			// List of characters 66 characters
			$chars = '1234567890!@#$%^&*()~`-_=+?;:><,./\\|[]{}qwertyuiopasdfghjklzxcvbnmQWERTYUIOASDFGHJKLZXCVBNM';
			
			// Empty salt
			$salt = '';
			
			// Iterate string
			for ( $i = $lenght; $i > 0; $i --)
			{
				// Add random character to array
				$salt .= $chars[mt_rand( 0, 90)];
			}
		}
		else
		{
			// Salt is random stirng from md5 for someting random
			$salt = substr( md5( mt_rand( 0, 10).time().mt_rand( 0, 10)), mt_rand( 0, 32 - $lenght), $lenght);
			
			// Salt Lenght
			$salt_l = strlen( $salt);
			
			// Random characters to uppercase
			for ( $i = 0; $i < $salt_l; $i ++)
			{
				// Make Uppercase?
				if ( mt_rand( 0, 1) == 1)
				{
					$salt[$i] = strtoupper( $salt[$i]);
				}
			}
		}
		
		// Return complete salt
		return $salt;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * DB secure function wrapper
	 *
	 * @param string $string
	 * @param bool $in_like
	 * @return string
	 */
	
	function strEscape( $string, $in_like = false){
		
		return $this -> db -> strEscape( $string, $in_like);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Escapes quotes in string for JS
	 *
	 * @param string $string
	 * @param integer $mode ( 0 - both, 1 - single, 2 - double)
	 * @return string
	 */
	
	function addSlashes( $string, $mode = 0){
		
		// All quotes?
		if ( $mode == 2)
		{
			// Escape double quotes
			return str_replace( '"', '\"', $string);
		}
		else if ( $mode == 1)
		{
			// Escape single quotes
			return str_replace( "'", "\'", $string);
		}
		else
		{
			// Escape all quotes
			return $this -> db -> secureStr( $string);	
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * This function sends redirect header to client
	 *
	 * @param string $url
	 * @param string $wait
	 */
	
	function setRedirect( $url, $wait = true){
		
		// Wait and use refresh?
		if ( !$wait || $this -> conf['redirections_instant'])
		{
			// Header: Location
			header( 'Location: '.str_replace( '&amp;', '&', $url));
		}
		else
		{
			// Header: Refresh
			header( 'Refresh: 3; url='.str_replace( '&amp;', '&', $url));
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * This function sends redirect header to client
	 *
	 * @param string $file_type
	 * @param string $file_size
	 * @param string $file_name
	 */
	
	function fileHeaders( $file_type, $file_size, $file_name){
		
		// No Cache allowed
		header( 'Cache-Control: no-cache, must-revalidate');
		header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT');
		
		// File Mime
		header('Content-type: ' . $file_size);
		header('Content-Disposition: attachment; filename="' . $file_name . '"');
		header('Content-Length: ' . $file_size);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Validates request using session code
	 *
	 * @param bool $use_post
	 * @return bool
	 */
	
	function validRequest( $use_post = true){
		
		// Do check
		if ( ( $use_post ? $this -> _POST( $this -> session -> session_key) : $this -> _GET( $this -> session -> session_key)) == $this -> session -> session_code)
		{
			// Action code match
			return true;
		}
		else
		{
			// Action code dont match
			return false;
		}
	
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Returns current action code
	 *
	 * @return string
	 */
	
	function actCode(){
		
		return $this -> session -> session_code;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Turns timestamp into human-understandable date
	 *
	 * @param integer $time
	 * @param string $format
	 * @param bool $allow_relative
	 * @return string
	 */
	
	function getDate( $time, $format = 'long', $allow_relative = true){
		
		// Use relative date?
		if ( $allow_relative && $this -> conf['board_date_relative_use'] && $this -> time - $time > -86400 && $this -> time - $time < 86400)
		{
			// Count difference
			$diff = $this -> time - $time;
			
			// Timespan
			if ( $diff == 0) // Now
			{
				// Return now
				return $this -> lang['date_now'];
			}
			else if ( $diff > 0 && $diff < 3600) // seconds or minutes ago
			{
				// Seconds ago?
				if ( $diff < 60)
				{
					return $diff . $this -> lang['date_seconds_ago'];
				}
				else if ( $diff < 3600)
				{
					return ceil( $diff / 60) . $this -> lang['date_minutes_ago'];
				}
			}
			else if ( gmdate( 'z-Y', $time) == gmdate( 'z-Y', $this -> time)) // Today
			{
				// Add timezone to time
				$time += $this -> time_zone;
				
				// Use DST?
				if ( $this -> time_dst)
				{
					// Detect DST
					if ( gmdate( 'I', $time) == 1)
					{
						// Add one more hour
						$time += 3600;
					}
				}
		
				return str_ireplace( '{-}', $this -> lang['date_today'], $this -> translateDate( gmdate( $this -> conf['board_date_relative'], $time)));
			}
			else if ( $diff > 0) // Yesterday
			{
				// Add timezone to time
				$time += $this -> time_zone;
				
				// Use DST?
				if ( $this -> time_dst)
				{
					// Detect DST
					if ( gmdate( 'I', $time) == 1)
					{
						// Add one more hour
						$time += 3600;
					}
				}
		
				return str_ireplace( '{-}', $this -> lang['date_yesterday'], $this -> translateDate( gmdate( $this -> conf['board_date_relative'], $time)));
			}
			else // Tomorrow
			{
				// Add timezone to time
				$time += $this -> time_zone;
				
				// Use DST?
				if ( $this -> time_dst)
				{
					// Detect DST
					if ( gmdate( 'I', $time) == 1)
					{
						// Add one more hour
						$time += 3600;
					}
				}
		
				return str_ireplace( '{-}', $this -> lang['date_tomorrow'], $this -> translateDate( gmdate( $this -> conf['board_date_relative'], $time)));
			}
		}
		else
		{
			// Add timezone to time
			$time += $this -> time_zone;
			
			// Use DST?
			if ( $this -> time_dst && date( 'I') == 1)
			{
				// Add one more hour
				$time += 3600;
			}
			
			// Return date
			return $this -> translateDate( gmdate( ( isset( $this -> conf['board_date_' . $format]) ? $this -> conf['board_date_' . $format] : $format), $time));
		}
		
	}
	
	/**
	 * Counts number of hours/days/months/years since something
	 *
	 * @param integer $org_time
	 * @return string
	 */
	
	function getAge( $org_time){
		
		// Turn time into difference
		$time = $this -> time - $org_time;
		
		// Time is not in future?
		if ( $time >= 0)
		{
			// Decide on items to display
			if ( $time < 60)
			{
				// Seconds
				return ( $time == 1 ? $this -> lang['date_age_second'] : sprintf($this -> lang['date_age_seconds'], $time));
			}
			else if ( $time < 3600)
			{
				// Count primary time
				$primary = floor($time / 60);
				
				// Count secondary time
				$secondary = ($time - (floor($time / 60) * 60));
				
				// Minutes and Seconds
				return ($primary == 1 ? $this -> lang['date_age_minute'] : sprintf($this -> lang['date_age_minutes'], $primary)) . ( $secondary == 0 ? '' : ' ' . $this -> lang['and'] .  ' ' . ($secondary == 1 ? $this -> lang['date_age_second'] : sprintf($this -> lang['date_age_seconds'], $secondary)));
			}
			else if ( $time < 86400)
			{
				// Count primary time
				$primary = floor($time / 3600);
				
				// Count secondary time
				$secondary = floor(($time - (floor($time / 3600) * 3600)) / 60);
				
				// Hours and Minutes
				return ($primary == 1 ? $this -> lang['date_age_hour'] : sprintf($this -> lang['date_age_hours'], $primary)) . ( $secondary == 0 ? '' : ' ' . $this -> lang['and'] .  ' ' . ($secondary == 1 ? $this -> lang['date_age_minute'] : sprintf($this -> lang['date_age_minutes'], $secondary)));
			}
			else if ( $time < 604800)
			{
				// Count primary time
				$primary = floor($time / 86400);
				
				// Count secondary time
				$secondary = floor(($time - (floor($time / 86400) * 86400)) / 3600);
				
				// Days and Hours
				return ($primary == 1 ? $this -> lang['date_age_day'] : sprintf($this -> lang['date_age_days'], $primary)) . ( $secondary == 0 ? '' : ' ' . $this -> lang['and'] .  ' ' . ($secondary == 1 ? $this -> lang['date_age_hour'] : sprintf($this -> lang['date_age_hours'], $secondary)));
			}
			else if ( $time < 1814400)
			{
				// Count primary time
				$primary = floor($time / 604800);
				
				// Count secondary time
				$secondary = floor(($time - (floor($time / 604800) * 604800)) / 86400);
				
				// Days and Hours
				return ($primary == 1 ? $this -> lang['date_age_week'] : sprintf($this -> lang['date_age_weeks'], $primary)) . ( $secondary == 0 ? '' : ' ' . $this -> lang['and'] .  ' ' . ($secondary == 1 ? $this -> lang['date_age_day'] : sprintf($this -> lang['date_age_days'], $secondary)));
			}
			else
			{
				// Same Year?
				if ( gmdate('Y') == gmdate('Y', $org_time))
				{
					// Count primary time
					$primary = gmdate('n') - gmdate('n', $org_time);
					
					// Count secondary time
					$secondary = floor((gmdate('W') - gmdate('W', $org_time)) / 7);
					
					// Months and Weeks
					return ($primary == 1 ? $this -> lang['date_age_month'] : sprintf($this -> lang['date_age_months'], $primary)) . ( $secondary == 0 ? '' : ' ' . $this -> lang['and'] .  ' ' . ($secondary == 1 ? $this -> lang['date_age_week'] : sprintf($this -> lang['date_age_weeks'], $secondary)));
				}
				else
				{
					// Count primary time
					$primary = gmdate('Y') - gmdate('Y', $org_time);
					
					// Count secondary time
					$secondary = (gmdate('n') + 12 - gmdate('n', $org_time));
					
					// Months and Weeks
					return ($primary == 1 ? $this -> lang['date_age_year'] : sprintf($this -> lang['date_age_years'], $primary)) . ( $secondary == 0 ? '' : ' ' . $this -> lang['and'] .  ' ' . ($secondary == 1 ? $this -> lang['date_age_month'] : sprintf($this -> lang['date_age_months'], $secondary)));
				}
			}
		}
		else
		{
			// Return nothing
			return NULL;
		}
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Translates date
	 *
	 * @param string $raw
	 * @return string
	 */
	
	function translateDate( $raw){

		// Translate date?
		if ( $this -> lang['date_use_translate'])
		{
			// Translate Months
			$raw = str_replace( 'January'		, $this -> lang['date_january'], $raw);
			$raw = str_replace( 'February'		, $this -> lang['date_february'], $raw);
			$raw = str_replace( 'March'		, $this -> lang['date_march'], $raw);
			$raw = str_replace( 'April'		, $this -> lang['date_april'], $raw);
			$raw = str_replace( 'May'			, $this -> lang['date_may'], $raw);
			$raw = str_replace( 'June'			, $this -> lang['date_june'], $raw);
			$raw = str_replace( 'July'			, $this -> lang['date_july'], $raw);
			$raw = str_replace( 'August'		, $this -> lang['date_august'], $raw);
			$raw = str_replace( 'September'	, $this -> lang['date_september'], $raw);
			$raw = str_replace( 'October'		, $this -> lang['date_october'], $raw);
			$raw = str_replace( 'November'		, $this -> lang['date_november'], $raw);
			$raw = str_replace( 'December'		, $this -> lang['date_december'], $raw);
			
			$raw = str_replace( 'Jan'			, $this -> lang['date_january_s'], $raw);
			$raw = str_replace( 'Feb'			, $this -> lang['date_february_s'], $raw);
			$raw = str_replace( 'Mar'			, $this -> lang['date_march_s'], $raw);
			$raw = str_replace( 'Apr'			, $this -> lang['date_april_s'], $raw);
			$raw = str_replace( 'May'			, $this -> lang['date_may_s'], $raw);
			$raw = str_replace( 'Jun'			, $this -> lang['date_june_s'], $raw);
			$raw = str_replace( 'Jul'			, $this -> lang['date_july_s'], $raw);
			$raw = str_replace( 'Aug'			, $this -> lang['date_august_s'], $raw);
			$raw = str_replace( 'Sep'			, $this -> lang['date_september_s'], $raw);
			$raw = str_replace( 'Oct'			, $this -> lang['date_october_s'], $raw);
			$raw = str_replace( 'Nov'			, $this -> lang['date_november_s'], $raw);
			$raw = str_replace( 'Dec'			, $this -> lang['date_december_s'], $raw);
			
			// Translate Days
			$raw = str_replace( 'Monday'		, $this -> lang['date_monday'], $raw);
			$raw = str_replace( 'Tuesday'		, $this -> lang['date_tuesday'], $raw);
			$raw = str_replace( 'Wednesday'	, $this -> lang['date_wednesday'], $raw);
			$raw = str_replace( 'Thursday'		, $this -> lang['date_thursday'], $raw);
			$raw = str_replace( 'Friday'		, $this -> lang['date_friday'], $raw);
			$raw = str_replace( 'Saturday'		, $this -> lang['date_saturday'], $raw);
			$raw = str_replace( 'Sunday'		, $this -> lang['date_sunday'], $raw);
			
			$raw = str_replace( 'Mon'			, $this -> lang['date_monday_s'], $raw);
			$raw = str_replace( 'Tue'			, $this -> lang['date_tuesday_s'], $raw);
			$raw = str_replace( 'Wed'			, $this -> lang['date_wednesday_s'], $raw);
			$raw = str_replace( 'Thu'			, $this -> lang['date_thursday_s'], $raw);
			$raw = str_replace( 'Fri'			, $this -> lang['date_friday_s'], $raw);
			$raw = str_replace( 'Sat'			, $this -> lang['date_saturday_s'], $raw);
			$raw = str_replace( 'Sun'			, $this -> lang['date_sunday_s'], $raw);
		}
		
		// Return ready date
		return $raw;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Returns list of time zones
	 *
	 * @param bool $full_list
	 * @return array
	 */
	
	function getTimeZones( $full_list = true){

		// Return Full List?
		if ( $full_list)
		{
			return array(
				-12 		=> $this -> lang['timezone_m12'],
				-11 		=> $this -> lang['timezone_m11'],
				-10 		=> $this -> lang['timezone_m10'],
				'-9.5' 		=> $this -> lang['timezone_m95'],
				-9	 		=> $this -> lang['timezone_m9'],
				-8	 		=> $this -> lang['timezone_m8'],
				-7	 		=> $this -> lang['timezone_m7'],
				-6 			=> $this -> lang['timezone_m6'],
				-5 			=> $this -> lang['timezone_m5'],
				'-4.5' 		=> $this -> lang['timezone_m45'],
				-4 			=> $this -> lang['timezone_m4'],
				'-3.5' 		=> $this -> lang['timezone_m35'],
				-3	 		=> $this -> lang['timezone_m3'],
				-2	 		=> $this -> lang['timezone_m2'],
				-1	 		=> $this -> lang['timezone_m1'],
				0	 		=> $this -> lang['timezone_0'],
				1	 		=> $this -> lang['timezone_1'],
				2	 		=> $this -> lang['timezone_2'],
				3	 		=> $this -> lang['timezone_3'],
				'3.5' 		=> $this -> lang['timezone_35'],
				4	 		=> $this -> lang['timezone_4'],
				'4.5' 		=> $this -> lang['timezone_45'],
				5	 		=> $this -> lang['timezone_5'],
				'5.5' 		=> $this -> lang['timezone_55'],
				'5.75' 		=> $this -> lang['timezone_575'],
				6	 		=> $this -> lang['timezone_6'],
				'6.5' 		=> $this -> lang['timezone_65'],
				7	 		=> $this -> lang['timezone_7'],
				8	 		=> $this -> lang['timezone_8'],
				'8.75' 		=> $this -> lang['timezone_875'],
				9	 		=> $this -> lang['timezone_9'],
				'9.5' 		=> $this -> lang['timezone_95'],
				10	 		=> $this -> lang['timezone_10'],
				'10.5' 		=> $this -> lang['timezone_105'],
				11	 		=> $this -> lang['timezone_11'],
				'11.5' 		=> $this -> lang['timezone_115'],
				12	 		=> $this -> lang['timezone_12'],
				'12.75'		=> $this -> lang['timezone_1275'],
				13	 		=> $this -> lang['timezone_13'],
				14			=> $this -> lang['timezone_14']
			);
		}
		else
		{
			return array(
				-12,
				-11,
				-10,
				'-9.5',
				-9,
				-8,
				-7,
				-6,
				-5,
				'-4.5',
				-4,
				'-3.5',
				-3,
				-2,
				-1,
				0,
				1,
				2,
				3,
				'3.5',
				4,
				'4.5',
				5,
				'5.5',
				'5.75',
				6,
				'6.5',
				7,
				8,
				'8.75',
				9,
				'9.5',
				10,
				'10.5',
				11,
				'11.5',
				12,
				'12.75',
				13,
				14
			);
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Counts Timestamp by day, month and year
	 *
	 * @param integer $year
	 * @param integer $month
	 * @param integer $day
	 * @return integer
	 */
	
	function getTimestamp( $year, $month, $day){
		
		// Count GM
		return gmmktime( 0, 0, 0, $month, $day, $year);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Secures file name
	 *
	 * @param string $string
	 * @param string $def_name
	 * @param string $space
	 * @return string
	 */
	
	function secureFilename( $string, $def_name = 'file', $space = '_'){
		
		// Filename with path?
		if ( strpos( $string, '/') !== false){
			$string = substr( $string, strrpos( $string, '/') + 1);
		}
		
		if ( strpos( $string, '\\') !== false){
			$string = substr( $string, strrpos( $string, '\\') + 1);
		}
		
		// Strip additional characters from string
		$string = preg_replace( '#[^a-zA-Z0-9_\-\s]#', '', $string);
		
		// If file name is empty, we gotta set basic "file" string
		if ( !isset( $string[0]))
		{
			$string = $def_name;
		}
		
		// Replace spaces with lowstrikes
		return str_replace( ' ', $space, $string);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Make URL proper
	 *
	 * @param string $link
	 * @return string
	 */
	
	function fixLink( $link){
		
		// Lower case link
		$link_l = strtolower( $link);
		
		// Does url starts from javascript:?
		if ( substr( $link_l, 0, 11) == "javascript:")
		{
			// Strip javascript from url
			$link = substr( $link, 11);		
		}
					
		// Empty or domain-less?
		if ( strlen( $link) < 4 || ( strpos( $link, 'localhost') !== false && strpos( $link, '.') === false))
		{
			// Rewrite link to http
			$link = 'http://';	
		}
		else
		{
			// Check protocol type
			if ( substr( $link_l, 0, 7) != 'http://' && substr( $link, 0, 8) != 'https://' && substr( $link_l, 0, 6) != 'ftp://')
			{
				// Protocol is incorrect
				$link = 'http://'.$link;
			}					
		}
		
		// Remove brackets
		$link = str_replace( array('(', ')'), '', $link);
		
		// Return finished link
		return $link;
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Formats number
	 *
	 * @param string $text
	 * @return string
	 */
	
	function number( $number){

		// Should we parse text?
		if ( isset( $this -> lang['number_hundreds'][0]) || $this -> lang['number_decimal'] != '.')
		{
			// Decimals lenght
			if ( strpos( $number, '.') !== false)
			{
				// Decimals
				$decimals = (float) ( '0' . substr( $number, strpos( $number, '.')));
				
				// Format number
				return number_format( $number, ( strlen( $decimals) - 2), $this -> lang['number_decimal'], $this -> lang['number_hundreds']);	
			}
			else
			{
				// Format number
				return number_format( $number, 0, $this -> lang['number_decimal'], $this -> lang['number_hundreds']);		
			}		
		}
		else
		{
			// Return string as it is
			return $number;
		}
			
	}
	
	/**
	 * Parses raw extra into array of options
	 *
	 * @param string $raw_extra
	 * @param bool $translate
	 * @return string
	 */
	
	function parseExtra( $raw_extra, $translate = true){
		
		// Special extra?
		if ( $raw_extra == '#TIMEZONES#')
		{
			// Return timezones
			return $this -> getTimeZones();
		}
		else
		{
			// Explode extra by \n char
			$raw_extra = explode( "\n", $raw_extra);
			
			// New extra
			$done_extra = array();
			
			// Reiterate raw extra
			foreach ( $raw_extra as $raw_item)
			{
				// Extract id
				$id = trim( substr( $raw_item, 0, strpos( $raw_item, ':')));
				
				// And value
				if ($translate)
				{
					$value = $this -> ifString( trim( substr( $raw_item, 1 + strpos( $raw_item, ':'))));
				}
				else
				{
					$value = trim( substr( $raw_item, 1 + strpos( $raw_item, ':')));
				}
				
				// Not empty?
				if ( isset( $id[0]) && isset( $value[0]))
				{
					$done_extra[$id] = $value;
				}
			}
			
			// Return result
			return $done_extra;
		}
			
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Draws button
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @param string $form_element_class
	 * @return string
	 */
	
	function drawButton( $form_element_name, $form_element_value = null, $form_element_class = 'form_button_dark'){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_button( array( 'field_name' => $form_element_name, 'field_title' => $form_element_value, 'field_class' => $form_element_class));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws text input
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @param string $width
	 * @return string
	 */
		
	function drawTextInput( $form_element_name, $form_element_value = NULL, $width = ''){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_text_input( array( 'field_name' => $form_element_name, 'field_value' => $form_element_value, 'field_width' => $width));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws text input (password one)
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @param string $width
	 * @return string
	 */
		
	function drawPassInput( $form_element_name, $form_element_value = null, $width = ''){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_pass_input( array( 'field_name' => $form_element_name, 'field_value' => $form_element_value, 'field_width' => $width));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws select
	 *
	 * @param string $form_element_name
	 * @param array $form_elements
	 * @param string $select_element
	 * @param string $width
	 * @return string
	 */
	
	function drawList( $form_element_name, $form_elements = array(), $select_element = null, $width = '', $group_by = ''){

		// Elements list is array?
		if ( is_array( $form_elements))
		{
			// Drawed items
			$drawed_items = '';
			
			// Iterate list elements, turning them into options
			foreach ( $form_elements as $element_id => $element_value)
			{
				//element is array?
				if ( is_array( $element_value))
				{
					$drawed_items .= '<option value="' . $element_id . '"' . ( $element_id == $select_element ? ' selected' : '') . ' ' . ( isset( $element_value[1]) ? 'disabled' : '') . '>' . $element_value[0] . '</option>';
				}
				else
				{
					//simple draw
					$drawed_items .= '<option value="' . $element_id . '"' . ( $element_id == $select_element ? ' selected' : '') . '>' . $element_value . '</option>';
				}
			}
			
			// Return generated html
			return '<select class="form_list" id="' . $form_element_name . '" name="' . $form_element_name . '"' . ( empty( $width) ? '' : ' style="width: ' . ((int) $width). 'px"') . '>' . $drawed_items . '</select>';
		}
		else
		{
			// Return nothing
			return '';
		}
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws options only to put into select
	 *
	 * @param array $form_elements
	 * @param string $select_element
	 * @return string
	 */
	
	function drawRawList( $form_elements = array(), $select_element = null){

		// Elements list is array?
		if ( is_array( $form_elements))
		{
			// Drawed items
			$drawed_items = '';
			
			// Iterate list elements, turning them into options
			foreach ( $form_elements as $element_id => $element_value)
			{
				//element is array?
				if ( is_array( $element_value))
				{
					$drawed_items .= '<option value="' . $element_id . '"' . ( $element_id == $select_element ? ' selected' : '') . ' ' . ( isset( $element_value[1]) ? 'disabled' : '') . '>' . $element_value[0] . '</option>';
				}
				else
				{
					//simple draw
					$drawed_items .= '<option value="' . $element_id . '"' . ( $element_id == $select_element ? ' selected' : '') . '>' . $element_value . '</option>';
				}
			}
			
			// Return generated html
			return $drawed_items;
		}
		else
		{
			// Return nothing
			return '';
		}
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws multiple choice select
	 *
	 * @param string $form_element_name
	 * @param array $form_elements
	 * @param array $select_elements
	 * @return string
	 */
		
	function drawMultiList( $form_element_name, $form_elements = array(), $select_elements = array()){

		// Elements list is array?
		if ( is_array( $form_elements) && is_array( $select_elements))
		{
			// Drawed items
			$drawed_items = '';
			
			// Iterate elements
			foreach ( $form_elements as $element_id => $element_value)
			{
				// Draw element
				$drawed_items .= $this -> templates['form_inputs'] -> tpl_multilist_item( array( 'item_checked' => ( in_array( $element_id, $select_elements) ? true : false), 'value_id' => $element_id, 'item_title' => $element_value, 'value_name' => $form_element_name));
			}
			
			// Return generated html
			return $this -> templates['form_inputs'] -> tpl_multilist_body( array( 'multilist_items' => $drawed_items));
		}
		else
		{
			// Return nothing
			return '';
		}
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws text-area
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @return string
	 */
		
	function drawTextArea( $form_element_name, $form_element_value = null){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_text_area( array( 'field_name' => $form_element_name, 'field_value' => $form_element_value));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws Big full-width text-area we use for editing css, JS or templates
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @return string
	 */
		
	function drawBigTextArea( $form_element_name, $form_element_value = null){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_big_text_area( array( 'field_name' => $form_element_name, 'field_value' => $form_element_value));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws yes-no switch
	 *
	 * @param string $form_element_name
	 * @param bool $form_element_value
	 * @return string
	 */
		
	function drawYesNo( $form_element_name, $form_element_value = false){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_yes_no( array( 'field_name' => $form_element_name, 'field_value' => (bool) $form_element_value));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws radio button
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @param bool $form_element_select
	 * @return string
	 */
	
	function drawRadio( $form_element_name, $form_element_value, $form_element_select = false, $form_element_id = ''){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_radio( array( 'field_id' => $form_element_id, 'field_name' => $form_element_name, 'field_value' => $form_element_value, 'field_select' => (bool) $form_element_select));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws checkbox
	 *
	 * @param string $form_element_name
	 * @param bool $form_element_select
	 * @param string $form_element_class
	 * @return string
	 */
	
	function drawCheckbox( $form_element_name, $form_element_select = false, $form_element_class = ''){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_check_box( array( 'field_name' => $form_element_name, 'field_select' => (bool) $form_element_select, 'field_class' => $form_element_class));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws checkbox
	 *
	 * @param string $form_element_name
	 * @param bool $form_element_select
	 * @param string $form_element_class
	 * @return string
	 */
		
	function drawFileUpload( $form_element_name, $width = 170){

		// Return generated html
		return $this -> templates['form_inputs'] -> tpl_file_upload( array( 'field_name' => $form_element_name, 'field_width' => $width));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Draws hidden field
	 *
	 * @param string $form_element_name
	 * @param string $form_element_value
	 * @return string
	 */
			
	function drawHidden( $form_element_name, $form_element_value = ''){

		// Return generated html
		return '<input name="' . htmlspecialchars( $form_element_name) . '" id="' . htmlspecialchars( $form_element_name) . '" type="hidden" value="' . htmlspecialchars( $form_element_value) . '" />';
		
	}

	// ------------------------------------------------------------------------

	/**
	 * Loads Tasks from DB or Cache and returns html to run them
	 *
	 * @return string
	 */
	
	function runTasks(){
		
		// Our tasks launchers
		$tasks_launchers = '';
		
		// Load tasks from cache
		$tasks = (array) class_cache::loadCache( 'sheduled_tasks');
		
		// Cache not loaded?
		if ( class_cache::$load_error)
		{
			// Select Tasks
			$this -> db -> query( 'SELECT task_id, task_file, task_days, task_hours, task_minutes, task_next_run
			FROM ' . DB_PREFIX . 'tasks
			WHERE task_active = \'1\'');
			
			// Build taks array from result
			while ( $task_result = $this -> db -> fetch_array())
			{
				$tasks[] = $task_result;
			}
			
			// Free Result
			$this -> db -> freeResult();
			
			// Save Cache
			class_cache::saveCache( 'sheduled_tasks', $tasks);
		}
		
		// Reiterate tasks
		$tasks_lenght = count( $tasks);
		
		// Build launchers list?
		if ( $tasks_lenght > 0)
		{
			for ( $t = 0; $t < $tasks_lenght; $t ++)
			{
				// Run Time All-right?
				if ( $tasks[$t][5] <= $this -> time)
				{
					// Launch task
					$tasks_launchers .= '<img src="' . APP_TASK_LAUNCHER . '?t=' . $tasks[$t][0] . '" width="1" height="1" borde="0" alt="" title="" />';
				}
			}
		}
		
		// Return ready string
		return $tasks_launchers;
		
	}

	// ------------------------------------------------------------------------

	/**
	 * Keeps script running after connection abort
	 *
	 */
	
	function stayAlive(){
		
		// Ignore user abort and keep running
		if ( function_exists( ' ignore_user_abort'))
		{
			 ignore_user_abort( true);	
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Loads styles and puts them into cache stare
	 *
	 */
	
	function loadStyles(){
		
		// Styles in cache store?
		if ( !isset( $this -> cache_store['styles']))
		{
			// Load styles from cache
			$this -> cache_store['styles'] = class_cache::loadCache( 'styles');
			
			// Load unsuccessful?
			if ( class_cache::$load_error)
			{
				// Styles list (un-ondered)
				$this -> cache_store['styles'] = array();
				
				// Select styles from database
				$this -> db -> query( 'SELECT style_id, style_parent, style_name
				FROM ' . DB_PREFIX . 'styles
				ORDER BY style_parent, style_name');
				
				// Parse result
				while ( $style_result = $this -> db -> fetch_assoc())
				{
					// Create empty parent array
					if ( !isset( $this -> cache_store['styles'][$style_result['style_parent']]))
					{
						$styles_list[$style_result['style_parent']] = array();
					}
					
					// Fix style name
					$style_result['style_name'] = htmlspecialchars( $style_result['style_name']);
					
					// Add style to array
					$this -> cache_store['styles'][$style_result['style_parent']][$style_result['style_id']] = $style_result;
				}
				
				// Free result
				$this -> db -> freeResult();
				
				// Order styles
				$this -> cache_store['styles'] = class_hierarchy::doOrdering( $this -> cache_store['styles']);
				
				// Save them in cache
				class_cache::saveCache( 'styles', $this -> cache_store['styles']);
			}
		}
		
	}
			
	// ------------------------------------------------------------------------
	
	/**
	 * Returns array with styles, that can be used for lists
	 *
	 * @param bool $with_master
	 * @param integer $except
	 * @return array
	 */
	
	function getStyles( $with_master, $except = 0){
		
		// Styles in cache store?
		if ( !isset( $this -> cache_store['styles']))
		{
			// Load styles
			$this -> loadStyles();
		}
		
		// Ready array
		$ready_array = array();
				
		// Except style?
		if ( $except > 0 && isset( $this -> cache_store['styles'][$except]))
		{
			// Item depth
			$item_depth = 0;
			
			// Adding?
			$adding = true;
			
			// Reiterate styles
			foreach ( $this -> cache_store['styles'] as $style_data)
			{
				// Decrease item depth by one?
				if ( !$with_master)
				{
					$style_data['item_depth'] --;
				}
				
				// Start adding?
				if ( $item_depth == $style_data['item_depth'])
				{
					$adding = true;
				}
				
				// Our current style?
				if ( $style_data['style_id'] == $except)
				{
					// Stop adding
					$adding = false;
					
					// Set depth
					$item_depth = $style_data['item_depth'];
				}
				
				// Add item?
				if ( $adding)
				{
					$ready_array[$style_data['style_id']] = ( $style_data['item_depth'] > 0 ? str_repeat( '- - ', $style_data['item_depth']) : '') . $style_data['style_name'];
				}
			}
		}
		else
		{
			// Reiterate styles
			foreach ( $this -> cache_store['styles'] as $style_data)
			{
				// Decrease item depth by one?
				if ( !$with_master)
				{
					$style_data['item_depth'] --;
				}
				
				// Return item
				$ready_array[$style_data['style_id']] = ( $style_data['item_depth'] > 0 ? str_repeat( '- - ', $style_data['item_depth']) : '') . $style_data['style_name'];
			}
		}
		
		// Delete master?
		if ( !$with_master)
		{
			unset( $ready_array[1]);
		}
		
		// Return array
		return $ready_array;
		
	}
	
	// ------------------------------------------------------------------------
		
	/**
	 * Returns array with style parents
	 *
	 * @param integer $style_id
	 * @return array
	 */
	
	function getStyleParents( $style_id){
		
		// Styles in cache store?
		if ( !isset( $this -> cache_store['styles']))
		{
			// Load styles
			$this -> loadStyles();
		}
		
		// Ready array
		$ready_array = array();
		
		// Style id in array?
		if ( isset( $this -> cache_store['styles'][$style_id]))
		{
			// Add our style to array
			$ready_array[] = $style_id;
			
			// Reiterate styles list while we are not in Master
			while ( $style_id != 1)
			{
				// Overwrite Style Id
				$style_id = $this -> cache_store['styles'][$style_id]['style_parent'];
				
				// Add styles parent to array
				$ready_array[] = $style_id;
			}
		}
		
		// Return array
		return $ready_array;
		
	}
	
	// ------------------------------------------------------------------------
		
	/**
	 * Returns array with style children
	 *
	 * @param integer $style_id
	 * @return array
	 */
	
	function getStyleChidren( $style_id){
		
		// Styles in cache store?
		if ( !isset( $this -> cache_store['styles']))
		{
			// Load styles
			$this -> loadStyles();
		}
		
		// Ready array
		$ready_array = array();
		
		// Style id in array?
		if ( isset( $this -> cache_store['styles'][$style_id]))
		{
			// Item depth
			$item_depth = 0;
			
			// Adding?
			$adding = false;
			
			// Reiterate styles
			foreach ( $this -> cache_store['styles'] as $style_data)
			{
				// Stop adding?
				if ( $adding && $style_data['item_depth'] == $item_depth)
				{
					// Break iteration
					break;
				}
				
				// Start adding?
				if ( $style_id == $style_data['style_id'])
				{
					// Start Adding
					$adding = true;
					
					// Set Item Depth
					$item_depth = $style_data['item_depth'];
				}
				
				// Add item?
				if ( $adding)
				{
					$ready_array[$style_data['style_id']] = $style_data['style_id'];
				}
			}
		}
		
		// Return array
		return $ready_array;
		
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Returns array with currently installed languages
	 *
	 * @return array
	 */
	
	function getLanguages(){
		
		// Store exists?
		if ( !isset( $this -> cache_store['languages']))
		{
			// Load cache
			$this -> cache_store['languages'] = class_cache::loadCache( 'languages');
			
			// No cache?
			if ( class_cache::$load_error)
			{
				// Ready array
				$ready_array = array();
				
				// Collect Languages
				$this -> db -> query( 'SELECT language_id, language_name
				FROM ' . DB_PREFIX . 'languages
				ORDER BY language_name');
				
				// Parse result
				while ( $lang_result = $this -> db -> fetch_array())
				{
					// Add language to cache store
					$this -> cache_store['languages'][$lang_result[0]] = htmlspecialchars( $lang_result[1]);
				}
				
				// Free result
				$this -> db -> freeResult();
				
				// Set cache
				class_cache::saveCache( 'languages', $this -> cache_store['languages']);
			}
		}
		
		// Return ready array
		return $this -> cache_store['languages'];
	
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Returns list of lang files script should have
	 *
	 * @param bool $with_modules
	 * @return array
	 */
	
	function getLanguageFiles( $with_modules = true){
		
		// Load source file
		require( LANGUAGE_FILES_MAP);
		
		// Return Lang strings
		return $lang_files;
		
	}
			
	// ------------------------------------------------------------------------
	
	/**
	 * Returns array with forums
	 *
	 * @param bool $for_list
	 * @param bool $permissions
	 * @param integer $except
	 * @return array
	 */
	
	function getForums( $for_list = false, $permissions = false, $except = 0){
		
		// Store exists?
		if ( !isset( $this -> cache_store['forums']))
		{
			// Load cache
			$this -> cache_store['forums'] = class_cache::loadCache( 'forums');
			
			// No cache?
			if ( class_cache::$load_error)
			{
				// Ready array
				$ready_array = array();
				
				// Collect Forums
				$this -> db -> query( 'SELECT forum_id, forum_parent, forum_name
				FROM ' . DB_PREFIX . 'forums
				ORDER BY  forum_pos');
				
				// Parse result
				while ( $forum_result = $this -> db -> fetch_assoc())
				{
					// Add Forum to array
					$this -> cache_store['forums'][$forum_result['forum_parent']][$forum_result['forum_id']] = $forum_result;
				}
				
				// Free result
				$this -> db -> freeResult();
				
				// Order Forums
				$this -> cache_store['forums'] = class_hierarchy::doOrdering( $this -> cache_store['forums']);
				
				// Set cache
				class_cache::saveCache( 'forums', $this -> cache_store['forums']);
			}
		}
		
		// For List?
		if ( $for_list)
		{
			// Make ready array
			$ready_array = array();
			
			// Adding stopped?
			$add_forum = true;
			$stop_depth = 0;
			
			// Fix them
			foreach ( $this -> cache_store['forums'] as $forum_id => $forum_data)
			{
				// Return to Adding
				if ($add_forum == false && $forum_data['item_depth'] <= $stop_depth)
				{
					$add_forum = true;
				}
				
				// Stop adding?
				if ($except > 0 && $except == $forum_id)
				{
					// Stop adding
					$add_forum = false;
					
					// Set depth
					$stop_depth = $forum_data['item_depth'];
				}
				
				// Add forum?
				if ($add_forum)
				{
					$ready_array[$forum_id] = ( $forum_data['item_depth'] > 0 ? str_repeat( '- - ', $forum_data['item_depth']) : '') . htmlspecialchars($forum_data['forum_name']);
				}
			}
			
			// Return ready array
			return $ready_array;
		}
		else
		{
			// Return raw array
			return $this -> cache_store['forums'];
		}
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Loads and returns permissions
	 *
	 * @return array
	 */
		
	function getPermissions(){
		
		// Store exists?
		if ( !isset( $this -> cache_store['permissions']))
		{
			// Load cache
			$this -> cache_store['permissions'] = class_cache::loadCache( 'permissions');
			
			// No cache?
			if ( class_cache::$load_error)
			{
				// Ready array
				$this -> cache_store['permissions'] = array();
				
				// Collect Permissions
				$this -> db -> query( 'SELECT *
				FROM ' . DB_PREFIX . 'permissions
				ORDER BY permission_pos');
				
				// Parse result
				while ( $perm_result = $this -> db -> fetch_assoc())
				{
					// Parse Extra
					$perm_result['permission_extra'] = $this -> parseExtra( $perm_result['permission_extra'], false);
					
					// Explode Arrays
					$perm_result['permission_force'] = explode( ',', $perm_result['permission_force']);
					$perm_result['permission_forbid'] = explode( ',', $perm_result['permission_forbid']);
					
					// Add language to cache store
					$this -> cache_store['permissions'][$perm_result['permission_id']] = $perm_result;
				}
				
				// Free result
				$this -> db -> freeResult();
				
				// Set cache
				class_cache::saveCache( 'permissions', $this -> cache_store['permissions']);
			}
			
			// Reiterate perms
			foreach ($this -> cache_store['permissions'] as $perm_id => $perm_data)
			{
				// Reiterate extra
				foreach ($perm_data['permission_extra'] as $extra_id => $extra_name)
				{
					// Translate teh extra
					$this -> cache_store['permissions'][$perm_id]['permission_extra'][$extra_id] = $this -> ifString($extra_name);
				}
			}
		}
		
		// Return ready array
		return $this -> cache_store['permissions'];
		
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Loads and returns Masks
	 *
	 * @return array
	 */
		
	function getMasks(){
		
		// Store exists?
		if ( !isset( $this -> cache_store['masks']))
		{
			// Load cache
			$this -> cache_store['masks'] = class_cache::loadCache( 'masks');
			
			// No cache?
			if ( class_cache::$load_error)
			{
				// Ready array
				$this -> cache_store['masks'] = array();
				
				// Collect Masks
				$this -> db -> query( 'SELECT mask_id, mask_name
				FROM ' . DB_PREFIX . 'permission_masks
				ORDER BY mask_name');
				
				// Parse result
				while ( $mask_result = $this -> db -> fetch_assoc())
				{
					// Add language to cache store
					$this -> cache_store['masks'][$mask_result['mask_id']] = $mask_result['mask_name'];
				}
				
				// Free result
				$this -> db -> freeResult();
				
				// Set cache
				class_cache::saveCache( 'masks', $this -> cache_store['masks']);
			}
			
			// Translate Masks
			foreach ( $this -> cache_store['masks'] as $mask_id => $mask_name)
			{
				$this -> cache_store['masks'][$mask_id] = $this -> ifString( $mask_name);
			}
		}
		
		// Return ready array
		return $this -> cache_store['masks'];
		
	}
		
	// ------------------------------------------------------------------------
	
	/**
	 * This function returns integer from inner counter
	 *
	 * @return integer
	 */
		
	function n(){
		
		// Increase counter
		$this -> number ++;
		
		// Return it
		return $this -> number;
		
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Logs admin action
	 *
	 * @param string $lang_key
	 * @param string $target
	 */
	
	function logAdmin( $log_content, $target = ''){
		
		// Insert
		$this -> db -> insert( array(
			'user_id' => $this -> user['id'],
			'user_name' => $this -> db -> strEscape( $this -> user['name']),
			'log_ip' => $this -> client_ip,
			'log_date' => $this -> time,
			'log_content' => $this -> db -> strEscape( $log_content),
			'log_target' => $this -> db -> strEscape( $target),
		), 'logs_admin');
		
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Logs ACP Access
	 *
	 * @param integer $id
	 * @param string $login
	 * @param bool $state
	 */
	
	function logAdminAccess( $id, $login, $state){
		
		// Insert
		$this -> db -> insert( array(
			'user_id' => $id,
			'user_name' => $this -> db -> strEscape( $login),
			'log_ip' => $this -> client_ip,
			'log_date' => $this -> time,
			'log_acces_state' => (bool) $state,
		), 'logs_admin_access');
		
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Checks if User ID/Email/IP is banned
	 *
	 * @param string $target
	 * @param bool $user
	 * @param bool $email
	 * @param bool $ip
	 * @return bool
	 */
	
	function checkBan( $target, $user = false, $email = false, $ip = false){
		
		// Load Banfilters?
		if ( !isset( $this -> cache_store['ban_filters']))
		{
			// Load teh cache
			$this -> cache_store['ban_filters'] = (array) class_cache::loadCache( 'bans');
			
			// Load failed?
			if ( class_cache::$load_error)
			{
				// Empty banfilters
				$this -> cache_store['ban_filters'] = array( 0 => array(), 1 => 0, 2 => array(), 3 => 0, 4 => array(), 5 => 0);
				
				// Select them from DB
				$this -> db -> query( 'SELECT user_id, ban_ip, ban_email, ban_reason_user, ban_lenght FROM ban_filters WHERE ban_lenght = \'0\' OR ban_lenght > \'' . $this -> time . '\'');
				
				// Put them into array
				while ( $ban_result = $this -> db -> fetch_assoc())
				{
					// Fix reason
					$ban_result['ban_reason_user'] = nl2br( htmlspecialchars( $ban_result['ban_reason_user']));
					
					// User Ban?
					if ( $ban_result['user_id'] > 0)
					{
						// Add ban to users results
						$this -> cache_store['ban_filters'][0][] = $ban_result;
						
						// Increase bans number
						$this -> cache_store['ban_filters'][1] ++;
					}
					else if ( isset( $ban_result['ban_ip'][0]))
					{
						// Add ban to IP results
						$this -> cache_store['ban_filters'][2][] = $ban_result;
						
						// Increase bans number
						$this -> cache_store['ban_filters'][3] ++;
					}
					else
					{
						// Add ban to E-Mail results
						$this -> cache_store['ban_filters'][4][] = $ban_result;
						
						// Increase bans number
						$this -> cache_store['ban_filters'][5] ++;						
					}
				}
				
				// Free result
				$this -> db -> freeResult();
				
				// Store Bans data
				class_cache::saveCache( 'bans', $this -> cache_store['ban_filters']);
				
			}
		}
		
		// Check User Ban
		if ( $user && $this -> cache_store['ban_filters'][1] > 0)
		{
			for ( $i = 0; $i < $this -> cache_store['ban_filters'][1]; $i ++)
			{
				// Ban Valid?
				if ( $this -> cache_store['ban_filters'][0][$i]['ban_lenght'] == 0 || $this -> cache_store['ban_filters'][0][$i]['ban_lenght'] > $this -> time)
				{
					// User is banned?
					if ( $this -> cache_store['ban_filters'][0][$i]['user_id'] == $target)
					{
						// Set Reason
						$this -> ban_reason = $this -> cache_store['ban_filters'][0][$i]['ban_reason_user'];
						
						// Return true
						return true;
					}
				}
			}
		}
		
		// Check IP Ban
		if ( $ip && $this -> cache_store['ban_filters'][3] > 0)
		{
			for ( $i = 0; $i < $this -> cache_store['ban_filters'][3]; $i ++)
			{
				// Ban Valid?
				if ( $this -> cache_store['ban_filters'][2][$i]['ban_lenght'] == 0 || $this -> cache_store['ban_filters'][2][$i]['ban_lenght'] > $this -> time)
				{
					// Exact match?
					if ( strpos( $this -> cache_store['ban_filters'][2][$i]['ban_ip'], '*') === false && $this -> cache_store['ban_filters'][2][$i]['ban_ip'] == $target)
					{
						// Set Reason
						$this -> ban_reason = $this -> cache_store['ban_filters'][2][$i]['ban_reason_user'];
						
						// Return true
						return true;
					}
					else
					{
						if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($this -> cache_store['ban_filters'][2][$i]['ban_ip'], '#')) . '$#i', $target))
						{
							// Set Reason
							$this -> ban_reason = $this -> cache_store['ban_filters'][2][$i]['ban_reason_user'];
							
							// Return true
							return true;
						}
					}
				}
			}
		}
		
		// Check E-Mail Ban
		if ( $email && $this -> cache_store['ban_filters'][5] > 0)
		{
			for ( $i = 0; $i < $this -> cache_store['ban_filters'][5]; $i ++)
			{
				// Ban Valid?
				if ( $this -> cache_store['ban_filters'][4][$i]['ban_lenght'] == 0 || $this -> cache_store['ban_filters'][4][$i]['ban_lenght'] > $this -> time)
				{
					// Exact match?
					if ( strpos( $this -> cache_store['ban_filters'][4][$i]['ban_email'], '*') === false && $this -> cache_store['ban_filters'][4][$i]['ban_email'] == $target)
					{
						// Set Reason
						$this -> ban_reason = $this -> cache_store['ban_filters'][4][$i]['ban_reason_user'];
						
						// Return true
						return true;
					}
					else
					{
						if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($this -> cache_store['ban_filters'][4][$i]['ban_email'], '#')) . '$#i', $target))
						{
							// Set Reason
							$this -> ban_reason = $this -> cache_store['ban_filters'][4][$i]['ban_reason_user'];
							
							// Return true
							return true;
						}
					}
				}
			}
		}
		
		// If we made it this far, its all-right
		return false;
		
	}
	
	// ------------------------------------------------------------------------
	
	/**
	 * Scale down dimensions
	 *
	 * @param integer $w_org
	 * @param integer $h_org
	 * @param integer $w_max
	 * @param integer $h_max
	 * @param bool $array
	 * @return mixed
	 */
	
	function scaleImage( $w_org, $h_org, $w_max = 0, $h_max = 0, $return_array = true){
				
		// Scale Width?
		if ( $w_max > 0 && $w_org > $w_max)
		{
			// Make Scale
			$scale = $w_max / $w_org;
			
			// Scale Width and Height Down
			$w_org = ceil($w_org * $scale);
			$h_org = ceil($h_org * $scale);
		}
				
		// Scale Height?
		if ( $h_max > 0 && $h_org > $h_max)
		{
			// Make Scale
			$scale = $h_max / $h_org;
			
			// Scale Width and Height Down
			$w_org = ceil($w_org * $scale);
			$h_org = ceil($h_org * $scale);
		}
		
		// Return result
		return ( $return_array ? array( $w_org, $h_org) : 'width="' . $w_org . '" height="' . $h_org . '"');
		
	}
	
	/**
	 * Checks if arrays contain same items
	 *
	 * @param array $array_a
	 * @param array $array_b
	 * @param bool $number
	 * @return mixed
	 */
	
	function arrays_collide( $array_a, $array_b, $number = false){
		
		// Collisions Number
		$collisions = 0;
		
		// Array A Lenght
		$array_l = count( $array_a);
		
		// Loop
		for ( $i = 0; $i < $array_l; $i ++)
		{
			// Array Item is in other array?
			if ( in_array( $array_a[$i], $array_b))
			{
				// Increase Collision or stop loop?
				if ( $number)
				{
					// Increase counter
					$collisions ++;
				}
				else
				{
					// Return true
					return true;
				}
			}
		}
		
		// Return result
		return ( $number ? $collisions : false);
		
	}
	
}

// God Object ends here. Before you will hop on forums
// to write that boring and uninteresing stuff like how
// God Object is anti-pattern, how I dont implement
// Magic methods in API classes, how i dont care about
// DRY, how MVC here is not real MVC, I am reinventing
// teh whell and should have used "better" framework
// read this:
// never gonna give you up, never gonna let you down,
// never gonna run around and desert you. Never gonna make you cry,
// never gonna say goodbye. Never gonna tell a lie and hurt you!
// U got RickRolled!